package com.hxzy.controller.front;

import cn.hutool.core.lang.UUID;
import com.hxzy.common.controller.BaseController;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.vo.R;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Administrator
 */
@Api(tags = "前端文件上传API")
@RestController
@RequestMapping(value = "/front")
@Log4j2
public class FrontUploadController extends BaseController {

    /**
     * 文件只支持格式
     */
    private final String[] IMAGE_EXT={"png","jpg","jpeg"};


    @ApiOperation(value = "图片上传(只支持png,jpg)")
    @PostMapping(value = "/image/upload")
    public R  imageUpload(@RequestPart(value = "file") MultipartFile file) throws IOException {

        if(file.isEmpty()){
            return R.build(AckCode.FILE_NOT_EMPTY);
        }

        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        TransferManager transferManager = createTransferManager();

        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        String bucketName = "waimai-1300180953";

        //文件名
        String oldFile=file.getOriginalFilename();
        //后缀名  jpg  png
        String ext= oldFile.substring(oldFile.lastIndexOf(".")+1);
        //不包含
        if(!Arrays.asList(IMAGE_EXT).contains(ext.toLowerCase())){
            return R.build(AckCode.UPLOAD_TYPE_ERROR_IMAGE);
        }

        R  r=null;

        // 对象键(Key)是对象在存储桶中的唯一标识 文件名。
        String key = "front_images/"+ UUID.fastUUID().toString()+"."+ext;

        //创建文件流
        // 这里创建一个 ByteArrayInputStream 来作为示例，实际中这里应该是您要上传的 InputStream 类型的流

        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
        // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
        objectMetadata.setContentLength(file.getSize());

        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file.getInputStream(),objectMetadata);


        try {
            // 高级接口会返回一个异步结果Upload
            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回 UploadResult, 失败抛出异常
            Upload upload = transferManager.upload(putObjectRequest);
            //返回结果
            UploadResult uploadResult = upload.waitForUploadResult();

            Map<String,String> map=new HashMap<>();
            map.put("name",oldFile);
            map.put("url",getUrl(uploadResult));

            r= R.okHasData(map);

        } catch (CosServiceException e) {
            log.error(e);
            r=R.build(AckCode.UPLOAD_FILE_CORRUPTED);
            r.setMsg(e.getMessage());

        } catch (CosClientException e) {
            log.error(e);
            r=R.build(AckCode.UPLOAD_FILE_CORRUPTED);
            r.setMsg(e.getMessage());

        } catch (InterruptedException e) {
            log.error(e);
            r=R.build(AckCode.UPLOAD_FILE_CORRUPTED);
            r.setMsg(e.getMessage());

        }finally {
            // 确定本进程不再使用 transferManager 实例之后，关闭之
            transferManager.shutdownNow(true);
        }

        //返回结果
        return r;
    }

    private String  getUrl(UploadResult uploadResult ){
        //https://waimai-1300180953.cos.ap-nanjing.myqcloud.com/images/1a89fa5a-0ad9-4b43-b5b2-a9155955b721.jpg
        StringBuffer str=new StringBuffer();
        str.append("https://").append(uploadResult.getBucketName()).append(".cos.ap-nanjing.myqcloud.com/").append(uploadResult.getKey());
        return str.toString();
    }

    /**
     * 创建 TransferManager 实例，这个实例用来后续调用高级接口
     * @return
     */
    private TransferManager createTransferManager() {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient();

        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(16);

        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);

        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5*1024*1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1*1024*1024);
        transferManager.setConfiguration(transferManagerConfiguration);

        return transferManager;
    }

    /**
     *  创建 COSClient 实例，这个实例用来后续调用请求
     * @return
     */
    private COSClient createCOSClient() {
        // 设置用户身份信息。
        // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
        //用户的 SecretId，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
        String secretId ="AKIDrSmZ6M199sOedNa2wyjCOIo3nKcdgowp";
        //用户的 SecretKey，建议使用子账号密钥，授权遵循最小权限指引，降低使用风险。子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
        String secretKey ="lHVsymIX2HFxNYR6UcT7UbS2PWS8gFhu";
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);

        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        // COS_REGION 请参见 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion(new Region("ap-nanjing"));

        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本，建议设置使用 https 协议
        // 5.6.54 及更高版本，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);

        // 以下的设置，是可选的：

        // 设置 socket 读取超时，默认 30s
        clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时，默认 30s
        clientConfig.setConnectionTimeout(30*1000);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }
}
